package com.mind.customer.handler.tongwei;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.mind.api.vo.OrderInfoResponse;
import com.mind.common.config.MindConfig;
import com.mind.common.constant.CustomerConstants;
import com.mind.common.utils.DateUtils;
import com.mind.common.utils.StringUtils;
import com.mind.common.utils.file.FileUtils;
import com.mind.common.utils.file.vo.FileVo;
import com.mind.customer.api.ocr.OCRUtils;
import com.mind.customer.api.oss.OSSUtils;
import com.mind.customer.config.FileConfig;
import com.mind.customer.domain.vo.HandlerData;
import com.mind.customer.domain.vo.HandlerDataResult;
import com.mind.customer.domain.vo.TaskResult;
import com.mind.customer.domain.vo.TickData;
import com.mind.customer.exception.AjObjectNotFoundException;
import com.mind.customer.handler.common.CommonHandler;
import com.mind.customer.mapper.AjObjectMapper;
import com.mind.customer.utils.CateUtils;
import com.mind.customer.utils.EnvUtils;
import com.mind.system.domain.AjAttachResult;
import com.mind.system.domain.AjObject;
import com.mind.system.domain.AjTicketTask;
import com.mind.system.domain.SysConfig;
import com.mind.system.domain.vo.Field;
import com.mind.system.mapper.AttachResultMapper;
import com.mind.system.mapper.SysConfigMapper;
import jakarta.annotation.Resource;
import lombok.extern.log4j.Log4j2;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.io.File;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * OCR处理器
 */
@Component
@Log4j2
public class OCRHandler {
    @Resource
    private SysConfigMapper sysConfigMapper;

    @Resource
    private OCRUtils ocrUtils;

    @Resource
    private AttachResultMapper attachResultMapper;

    @Resource
    private FileConfig fileConfig;

    @Resource
    private CommonHandler commonHandler;

    @Resource
    private StampHandler stampHandler;

    @Resource
    private AjObjectMapper objectMapper;

    @Resource
    private OSSUtils ossUtils;

    private String ocrFieldKey = "detail_words";

    @Resource
    private CateUtils cateUtils;

    @Resource
    private EnvUtils envUtils;


    /**
     * todo 拿到影像附件url进行ocr大模型识别分类，返回结构化的单据和合同信息，行程单.....
     * 只有图片没有原单数据也可以走ocr识别
     * 处理ocr的数据
     *
     * @param ocrFileList
     * @return
     */

    public TaskResult handler(AjTicketTask task, List<OrderInfoResponse.FileList> ocrFileList) throws Exception {
        List<String> ocrSupportFiles = getOcrSupportFiles();

        JSONObject result = new JSONObject();
        Map<String, Object> originalData = new HashMap<>();
        Set<String> existsObjectName = new HashSet<>();
        // 拼接文件集合
        String filePrefix = "mind" + DateUtils.dateTime();


        List<FileVo> lsFile = new ArrayList<>();
        for (OrderInfoResponse.FileList file : ocrFileList) {
            if (file.getFileExtension() == null) {
                log.error("文件格式错误：{}", file);
                continue;
            }
            // 下载附件
            FileVo fileVo = FileUtils.download(file.getFileUrl(), fileConfig.getBasePath() + filePrefix + "/", filePrefix, file.getFileExtension());
            fileVo.setFileName(file.getFileName());
            //fileVo.parseBase64Url();
            ossUtils.upload(fileVo.getFileName(), fileVo.getFilePath());
            lsFile.add(fileVo);
        }
        try {
            // 获取NC返回
            List<Map<String, String>> ncFileMap = ocrUtils.getNcData(lsFile, task);
            // OCR识别
            String filePath = "";
            attachResultMapper.execDeleteSql("delete from aj_report_files where report_no='" + task.getTicketId() + "'");
            for (Map<String, String> fileMap : ncFileMap) {
                // 下载文件
                filePath = fileConfig.getBasePath() + filePrefix + "/" + fileMap.get("fileName");
                FileUtils.base64ToFile(fileMap.get("base64"), filePath);
                fileMap.put("filePath", filePath);
                fileMap.put("fileApi", filePrefix + "/" + fileMap.get("fileName"));
                fileMap.put("fileApiUrl", MindConfig.getHost() + "/api/customer/file/" + fileMap.get("fileApi"));
                // 生成fileVo对象
                FileVo fileVo = new FileVo();
                fileVo.setApiUrl(MindConfig.getHost() + "/api/customer/file/" + fileMap.get("fileApi"));
                fileVo.setFilePath(filePath);
                fileVo.setFileName(fileMap.get("fileName"));
                AjAttachResult attachResult = packageSaveAttachResult(task, fileMap);
                // 插入report_files附件结果
                String fileId = "";
                String fileName = attachResult.getFileName();
                String fileType = "";
                String fileUrl = attachResult.getFileUrl();
                String fileJson = "";
                String fileNo = task.getTicketId();
                // reportResult结果集
                List<TickData> originalTickData = new ArrayList<>();
                JSONObject ocrResult = new JSONObject();
                List<TickData> ocrDataList;
                try {

                    ocrDataList = ocrUtils.ncGetTicketData2(task, fileMap, true);
                } catch (SocketTimeoutException e) {
                    log.error("{} OCR识别超时", fileMap, e);
                    attachResult.setStatus("OCR识别超时");
                    attachResultMapper.updateAttachResult(attachResult);
                    continue;
                } catch (Exception e) {
                    log.error("{} OCR未知异常", fileMap, e);
                    attachResult.setStatus("OCR识别接口识别未知异常");
                    attachResultMapper.updateAttachResult(attachResult);
                    continue;
                }
                if (CollectionUtils.isEmpty(ocrDataList)) {
                    log.error("{} 没有检测到附件分类", ncFileMap);
                    attachResult.setStatus("没有检测到附件分类");
                    attachResultMapper.updateAttachResult(attachResult);
                    continue;
                }
                for (TickData ocrData : ocrDataList) {
                    fileType = ocrData.getTickCate();
                    attachResult.setCostOcr(ocrData.getCostOcr());
                    attachResult.setCostContent(ocrData.getCostAi());
                    attachResult.setResult(ocrData.getOriginalData() == null ? "" : ocrData.getOriginalData().toJSONString());
                    fileJson = attachResult.getResult();
                    // 附件分类名称选择 附件名称，而不是附件分类名称
                    AjObject ajObject = objectMapper.selectObjectByName2(task.getTicketType() );
                    String attachType = ajObject.getAttachType();
                    List<AjObject> ajObjects = objectMapper.selectObjectBySourceId(attachType);
                    for (String s : attachType.split(",")) {
                        ajObjects.addAll(objectMapper.selectObjectBySourceId(s));
                    }
                    String tempTypeName = ocrData.getTickCate();
                    for (AjObject o : ajObjects) {
                        if (o.getTypeName() != null && o.getTypeName().equals(ocrData.getTickCate())) {
                            tempTypeName = o.getName();
                            break;
                        }
                    }
                    attachResult.setStatus(String.format("附件分类:%s, 附件模板名称：%s", tempTypeName, ocrData.getTickName()));
                    attachResultMapper.updateAttachResult(attachResult);
                    if (fileMap.get("fileType").toLowerCase().equals("pdf")) {
                        List<FileVo> imageUrlList = new ArrayList<>();
                        try {
                            imageUrlList = FileUtils.pdfToImage(new File(fileMap.get("fileType")), fileConfig.getBasePath() + filePrefix + "/", filePrefix);
                        } catch (Exception e) {
                            log.error("{} pdf转图片失败", fileMap, e);
                            attachResult.setResult("pdf转图片失败");
                            attachResultMapper.updateAttachResult(attachResult);
                            continue;
                        }
                        int index = 0;
                        // 统计pdf页数
                        attachResult.setPdfPages(imageUrlList.size());
                        attachResultMapper.updateAttachResult(attachResult);
                        for (FileVo f : imageUrlList) {
                            ossUtils.upload(f.getFileName(), f.getFilePath());
                            if (StringUtils.isNotNull(ocrData.getBoxes())) {
                                f.setBoxes(ocrData.getBoxes().getJSONArray(index));
                            }
                            if (StringUtils.isNotNull(ocrData.getTexts())) {
                                f.setTexts(ocrData.getTexts().getJSONArray(index));
                            }
                            originalTickData.add(ocrData);
                            index++;
                        }
                        fileVo.setChildren(imageUrlList);
                    } else {
                        if (StringUtils.isNotNull(ocrData.getBoxes())) {
                            fileVo.setBoxes(ocrData.getBoxes().getJSONArray(0));
                        }
                        if (StringUtils.isNotNull(ocrData.getTexts())) {
                            fileVo.setTexts(ocrData.getTexts().getJSONArray(0));
                        }
                        originalTickData.add(ocrData);
                    }
                    try {
                        // OCR识别结果-mapping成对象信息
                        ocrResult.putAll(handleOCR(task, ocrData, fileVo));
                        // 20250507-add
                        fileVo.setSourceUrl(attachResult.getSourceUrl());
                        ocrResult.put("fileVo", fileVo);
                    } catch (AjObjectNotFoundException e) {
                        log.error("文件对象：{}, ocrData: {}, 发生异常", fileVo, ocrData, e);
                    }

                    // 汇总
                    if (ocrResult.containsKey("objectName")) {
                        String objectName = ocrResult.getString("objectName");
                        existsObjectName.add(objectName);
                        if (!result.containsKey(objectName)) {
                            result.put(objectName, new JSONArray());
                        }
                        result.getJSONArray(objectName).add(ocrResult);
                        originalData.put("/api/customer/file/" + fileMap.get("fileApi"), originalTickData);
                    }
                }
                // 插入report_files附件结果
                if (fileType.equals("餐饮小票")) {
                    // 后处理
                    if (fileJson != null && fileJson.length() > 0) {
                        try {
                            JSONObject jsonObject = JSONObject.parse(fileJson);
                            fileId = jsonObject.getString("编号");
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
                attachResultMapper.execInsertSql("INSERT INTO aj_report_files (file_id,file_name,file_type,file_path,file_json,report_no,update_date,create_date,remarks) \n" +
                        "VALUES('" + fileId + "','" + fileName + "','" + fileType + "','" + fileUrl + "','" + fileJson + "','" + fileNo + "',now(),now(),'')");
            }
        } catch (SocketTimeoutException e) {
            log.error("{} ocr识别超时", lsFile, e);
        } catch (Exception e) {
            log.error("{} ocr未知异常", lsFile, e);
        }


        // 自动补全ObjectExist
        autoCompleteObjectExists(result, existsObjectName, task);
        return new TaskResult() {{
            setStatus(1);
            setOriginalData(new HashMap<String, Object>() {{
                put("ocr", originalData);
            }});
            setData(result);
        }};
    }

    /**
     * 自动补全
     *
     * @param result
     * @param existsObjectName
     * @param task
     */
    private void autoCompleteObjectExists(JSONObject result, Set<String> existsObjectName, AjTicketTask task) {
        // 查出对应单据类型的对象并自动补全
        List<AjObject> lsObject = objectMapper.selectObjectList(new AjObject() {{
            setTicketType(task.getTicketType());
        }});
        for (AjObject obj : lsObject) {
            List<Field> fields = JSONArray.parseArray(obj.getFields(), Field.class);
            // 判断有没有固定字段ObjectExists
            List<Field> objectExists = fields.stream().filter(field -> field.getAttachmentDataField() != null).filter(field ->
                    Arrays.asList(field.getAttachmentDataField().split(",")).contains("ObjectExist")
            ).collect(Collectors.toList());
            // 需要补全
            if (objectExists.size() > 0) {

                if (!existsObjectName.contains(obj.getName())) {
                    result.put(obj.getName(), new JSONArray() {
                        {
                            add(new JSONObject() {{
                                put(objectExists.get(0).getRuleDataField(), "否");
                                fields.stream().filter(field -> StringUtils.isNotEmpty(field.getDefaultValue())).forEach(f -> {
                                    put(f.getRuleDataField(), f.getDefaultValue());
                                });

                                List<Field> children = fields.stream().filter(field -> field.getChildren().size() > 0).collect(Collectors.toList());
                                for (Field child : children) {
                                    JSONArray jsonArray = new JSONArray();
                                    JSONObject jsonObject = new JSONObject();
                                    for (Field field : child.getChildren()) {
                                        if (StringUtils.isNotEmpty(field.getDefaultValue())) {
                                            jsonObject.put(field.getRuleDataField(), field.getDefaultValue());
                                        }
                                    }
                                    if (jsonObject.size() > 0) {
                                        jsonArray.add(jsonObject);
                                        put(child.getRuleDataField(), jsonArray);
                                    }
                                }
                            }});

                        }
                    });

                } else {
                    JSONArray jsonArray = new JSONArray();
                    result.getJSONArray(obj.getName()).forEach(json -> {
                        JSONObject jsonObject = (json instanceof JSONObject) ? (JSONObject) json : JSONObject.parseObject(json.toString());
                        jsonObject.put(objectExists.get(0).getRuleDataField(), "是");
                        jsonArray.add(jsonObject);
                    });
                    result.put(obj.getName(), jsonArray);
                }
            }
        }
    }

    private JSONObject handleOCR(AjTicketTask task, TickData ocrData, FileVo fileVo) throws AjObjectNotFoundException, IOException {
        JSONObject ocrResult = new JSONObject();
//        if (StringUtils.isNotEmpty(ocrData.getOriginalData())) {
       /* ocrData = preHandle(ocrData);
        List<AjObject> lsObject = objectMapper.selectObjectList(new AjObject() {{
            setTicketType(task.getTicketType());
        }});
        String tempTypeName = ocrData.getTickCate();
        for (AjObject ajObject : lsObject) {
            if (ajObject.getTypeName() != null && ajObject.getTypeName().equals(ocrData.getTickCate())) {
                tempTypeName = ajObject.getName();
                break;
            }
        }*/
        AjObject ajObject = objectMapper.selectObjectByName2(task.getTicketType() );
        String attachType = ajObject.getAttachType();
        List<AjObject> ajObjects = objectMapper.selectObjectBySourceId(attachType);
        for (String s : attachType.split(",")) {
            ajObjects.addAll(objectMapper.selectObjectBySourceId(s));
        }
        String tempTypeName = ocrData.getTickCate();
        for (AjObject o : ajObjects) {
            if (o.getTypeName() != null && o.getTypeName().equals(ocrData.getTickCate())) {
                tempTypeName = o.getName();
                break;
            }
        }
        try {
            // 封装印章数据

            JSONObject stampData = stampHandler.handler(task.getTicketType(),tempTypeName, ocrData.getTickName(), fileVo, task);
            if (stampData != null) {
                ocrData.getOriginalData().putAll(stampData);
            }
        } catch (AjObjectNotFoundException e) {
            log.error("处理印章数据失败", e);
        }
        TickData finalOcrData = ocrData;
        // 处理数据,ocr识别Mapping成object
        HandlerData handlerData = new HandlerData() {{
            setTickName(finalOcrData.getTickName());
            setTicketType(task.getTicketType());
            setOriginalData(new JSONArray(finalOcrData.getOriginalData()));
        }};
        handlerData.setTickCate(tempTypeName);
        handlerData.setTickName(tempTypeName);
        HandlerDataResult handlerDataResult = commonHandler.handleData(handlerData);
        ocrResult.putAll(handlerDataResult.getResult().getJSONObject(0));
        if (ocrData.getOriginalData().containsKey("SIGNATURE_STAMP")) {
            ocrData.getOriginalData().remove("SIGNATURE_STAMP");
        }
        if (!envUtils.getModel().equals("ND_VL")) {
            ocrResult.putAll(ocrData.getOriginalData());
        }
        ocrResult.put("objectName", handlerDataResult.getObject().getName());
//        }
        ocrResult.put("attachName", ocrData.getTickName());
        ocrResult.put("attachCate", ocrData.getTickCate());
        return ocrResult;
    }


    /**
     * 查询OCR支持文件后缀名
     *
     * @return
     */
    @NotNull
    public List<String> getOcrSupportFiles() {
        SysConfig sysConfig = sysConfigMapper.checkConfigKeyUnique("OCR_SUPPORT_FILE");
        List<String> ocrSupportFiles = Arrays.asList("pdf", "docx", "png", "jpeg", "jpg");
        if (StringUtils.isNotNull(sysConfig) && StringUtils.isNotEmpty(sysConfig.getConfigValue())) {
            String ocrSupportFileStr = sysConfig.getConfigValue();
            ocrSupportFiles = Arrays.asList(ocrSupportFileStr.split(","));
        }
        return ocrSupportFiles;
    }

    /**
     * 预处理ocrData
     *
     * @param ocrData
     * @return
     */
    private TickData preHandle(TickData ocrData) {
        JSONObject originalData = ocrData.getOriginalData();
        if (originalData.containsKey(ocrFieldKey)) {
            originalData.putAll(originalData.getJSONObject(ocrFieldKey));
        }
        ocrData.setOriginalData(originalData);
        return ocrData;
    }

    private AjAttachResult packageSaveAttachResult(AjTicketTask task, Map<String, String> fileMap) throws IOException {
        AjAttachResult result = new AjAttachResult() {{
            setTicketId(task.getTicketId());
            setVersion(task.getVersion());
            setFileName(fileMap.get("fileName"));
            setFileExtension(fileMap.get("fileType"));
            setFileUrl(fileMap.get("fileApiUrl"));
            setOriginId(fileMap.get("originId"));
            setSourceUrl(fileMap.get("sourceUrl"));
            setTicketType(cateUtils.getTicketTypeByCode(task.getTicketType()));
        }};

        if (!getOcrSupportFiles().contains(fileMap.get("fileType"))) {
            result.setStatus("忽略");
            packageOffice(fileMap, result);
        } else {
            // pdf 预览实现
            packageOffice(fileMap, result);
            result.setStatus("处理中");
        }

        attachResultMapper.insertAttachResult(result);
        return result;
    }

    /**
     * 打包并保存
     *
     * @param fileMap
     * @param result
     * @throws IOException
     */
    private void packageOffice(Map<String, String> fileMap, AjAttachResult result) throws IOException {
        if (CustomerConstants.OFFICE_LIST.contains(fileMap.get("fileType").toLowerCase())) {
            ossUtils.upload(fileMap.get("fileName"), fileMap.get("filePath"));
            result.setFileUrl("/api/customer/file/" + fileMap.get("fileApi"));
        }
    }


    private static void autoCompleteObjectExists2(JSONObject result, Set<String> existsObjectName) {
        // 查出对应单据类型的对象并自动补全
        List<AjObject> lsObject = new ArrayList<>();
        AjObject object = new AjObject();
        object.setName("餐饮小票");
        object.setFields("[{\"id\":\"m8wpd16c.151\",\"ruleDataField\":\"对象是否存在\",\"attachmentDataField\":\"ObjectExist\",\"fieldType\":\"text\",\"dataType\":\"header\",\"children\":[]},{\"id\":\"m8wpd16c.1242\",\"attachmentDataField\":\"编号\",\"ruleDataField\":\"编号\",\"fieldType\":\"text\",\"dataType\":\"header\",\"styleConfig\":{\"filedId\":\"m8wpd16c.1242\",\"isUse\":1,\"keyFontSize\":14,\"keyFontColor\":\"#333\",\"valueFontSize\":14,\"valueFontColor\":\"#333\"},\"defaultValue\":\"~\",\"children\":[]},{\"id\":\"m8wpddhi.1063\",\"attachmentDataField\":\"日期\",\"ruleDataField\":\"日期\",\"fieldType\":\"text\",\"dataType\":\"header\",\"styleConfig\":{\"filedId\":\"m8wpddhi.1063\",\"isUse\":1,\"keyFontSize\":14,\"keyFontColor\":\"#333\",\"valueFontSize\":14,\"valueFontColor\":\"#333\"},\"defaultValue\":\"~\",\"children\":[],\"attachmentDataDesc\":\"YYYY-MM-DD\"},{\"id\":\"m8wpdmh9.2654\",\"attachmentDataField\":\"商铺名称\",\"ruleDataField\":\"商铺名称\",\"fieldType\":\"text\",\"dataType\":\"header\",\"styleConfig\":{\"filedId\":\"m8wpdmh9.2654\",\"isUse\":1,\"keyFontSize\":14,\"keyFontColor\":\"#333\",\"valueFontSize\":14,\"valueFontColor\":\"#333\"},\"defaultValue\":\"~\",\"children\":[]},{\"id\":\"m8wpdt50.1749\",\"attachmentDataField\":\"实体店地址\",\"ruleDataField\":\"实体店地址\",\"fieldType\":\"text\",\"dataType\":\"header\",\"styleConfig\":{\"filedId\":\"m8wpdt50.1749\",\"isUse\":1,\"keyFontSize\":14,\"keyFontColor\":\"#333\",\"valueFontSize\":14,\"valueFontColor\":\"#333\"},\"defaultValue\":\"~\",\"children\":[],\"isIgnoreAttachmentData\":true},{\"id\":\"m8wpdzbe.1729\",\"attachmentDataField\":\"是否重复上传\",\"ruleDataField\":\"是否重复上传\",\"fieldType\":\"text\",\"dataType\":\"header\",\"styleConfig\":{\"filedId\":\"m8wpdzbe.1729\",\"isUse\":1,\"keyFontSize\":14,\"keyFontColor\":\"#333\",\"valueFontSize\":14,\"valueFontColor\":\"#333\"},\"defaultValue\":\"~\",\"children\":[],\"isIgnoreAttachmentData\":true},{\"id\":\"m8wpe403.1749\",\"attachmentDataField\":\"翻拍原因\",\"ruleDataField\":\"翻拍原因\",\"fieldType\":\"text\",\"dataType\":\"header\",\"styleConfig\":{\"filedId\":\"m8wpe403.1749\",\"isUse\":1,\"keyFontSize\":14,\"keyFontColor\":\"#333\",\"valueFontSize\":14,\"valueFontColor\":\"#333\"},\"defaultValue\":\"~\",\"children\":[],\"isIgnoreAttachmentData\":true},{\"id\":\"m8wpe7vt.397\",\"attachmentDataField\":\"是否翻拍\",\"ruleDataField\":\"是否翻拍\",\"fieldType\":\"text\",\"dataType\":\"header\",\"styleConfig\":{\"filedId\":\"m8wpe7vt.397\",\"isUse\":1,\"keyFontSize\":14,\"keyFontColor\":\"#333\",\"valueFontSize\":14,\"valueFontColor\":\"#333\"},\"defaultValue\":\"~\",\"children\":[],\"isIgnoreAttachmentData\":true}]");
        lsObject.add(object);
        for (AjObject obj : lsObject) {
            List<Field> fields = JSONArray.parseArray(obj.getFields(), Field.class);
            // 判断有没有固定字段ObjectExists
            List<Field> objectExists = fields.stream().filter(field -> field.getAttachmentDataField() != null).filter(field ->
                    Arrays.asList(field.getAttachmentDataField().split(",")).contains("ObjectExist")
            ).collect(Collectors.toList());
            // 需要补全
            if (objectExists.size() > 0) {

                if (!existsObjectName.contains(obj.getName())) {
                    result.put(obj.getName(), new JSONArray() {
                        {
                            add(new JSONObject() {{
                                put(objectExists.get(0).getRuleDataField(), "否");
                                fields.stream().filter(field -> StringUtils.isNotEmpty(field.getDefaultValue())).forEach(f -> {
                                    put(f.getRuleDataField(), f.getDefaultValue());
                                });

                                List<Field> children = fields.stream().filter(field -> field.getChildren().size() > 0).collect(Collectors.toList());
                                for (Field child : children) {
                                    JSONArray jsonArray = new JSONArray();
                                    JSONObject jsonObject = new JSONObject();
                                    for (Field field : child.getChildren()) {
                                        if (StringUtils.isNotEmpty(field.getDefaultValue())) {
                                            jsonObject.put(field.getRuleDataField(), field.getDefaultValue());
                                        }
                                    }
                                    if (jsonObject.size() > 0) {
                                        jsonArray.add(jsonObject);
                                        put(child.getRuleDataField(), jsonArray);
                                    }
                                }
                            }});

                        }
                    });

                } else {
                    JSONArray jsonArray = new JSONArray();
                    result.getJSONArray(obj.getName()).forEach(json -> {
                        JSONObject jsonObject = (json instanceof JSONObject) ? (JSONObject) json : JSONObject.parseObject(json.toString());
                        jsonObject.put(objectExists.get(0).getRuleDataField(), "是");
                        jsonArray.add(jsonObject);
                    });
                    result.put(obj.getName(), jsonArray);
                }
            }
        }
    }

    public static void main(String[] args) throws AjObjectNotFoundException, IOException {
        String jsonStr = "{\"Basic\":{\"单据编号\":\"CLBXD2024062105326\",\"单位名称\":\"国内区域中心\",\"部门名称\":\"华中区域中心\",\"报销人\":\"张斌强\",\"单据日期\":\"2024-06-21\",\"单据状态\":\"处理中\",\"经办人\":\"张斌强\",\"来源系统\":\"手工录入\",\"核算组织\":\"上海振华_国内区域中心\",\"发起方式\":\"web端\",\"本位币币种\":\"CNY-人民币\",\"报销金额（本位币）\":\"1,996.00\",\"核销借款（本位币）\":\"0.00\",\"实付金额（本位币）\":\"1,996.00\",\"挂账金额（本位币）\":\"0.00\",\"商旅金额（本位币）\":\"0.00\",\"附件张数\":\"1\",\"报销事由\":\"华中区域中心张斌强经手郑州国际陆港用户武汉住宿费\",\"备注\":\"用张斌强的名字代替郑州国际陆港用户3人\"},\"Detail\":{\"报销费用明细\":[{\"序号\":\"1\",\"出差人\":\"张斌强\",\"*出发日期\":\"2024-05-17\",\"*到达日期\":\"2024-05-17\",\"*出发地点\":\"郑州市\",\"*到达地点\":\"武汉市\",\"交通工具\":\"\",\"席位等级\":\"\",\"航班/车次\":\"\",\"*原币币种\":\"CNY-人民币\",\"*汇率\":\"1.000000\",\"汇率\":\"1.000000\",\"票价\":\"0.00\",\"民航基金\":\"0.00\",\"燃油附加费\":\"0.00\",\"其他税费\":\"0.00\",\"交通费\":\"0.00\",\"订票手续费\":\"0.00\",\"退改签费\":\"0.00\",\"保险费\":\"0.00\",\"商旅订单供应商名称\":\"\",\"商旅金额（本位币）\":\"0.00\",\"餐饮费\":\"0.00\",\"住宿费\":\"1996.00\",\"其他费用\":\"0.00\",\"出差天数\":\"0\",\"补助标准\":\"0.00\",\"补助金额\":\"0.00\",\"报销金额（原币）\":\"1,996.00\",\"报销金额（本位币）\":\"1,996.00\",\"来源\":\"手工录入\",\"总计\":\"1,996.00\",\"乘客身份证\":\"\",\"身份证号\":\"\",\"实报金额\":\"1,996.00\"},{\"序号\":\"2\",\"出差人\":\"张斌强\",\"*出发日期\":\"2024-06-18\",\"*到达日期\":\"2024-06-18\",\"*出发地点\":\"武汉市\",\"*到达地点\":\"郑州市\",\"交通工具\":\"\",\"席位等级\":\"\",\"航班/车次\":\"\",\"*原币币种\":\"CNY-人民币\",\"*汇率\":\"1.000000\",\"汇率\":\"1.000000\",\"票价\":\"0.00\",\"民航基金\":\"0.00\",\"燃油附加费\":\"0.00\",\"其他税费\":\"0.00\",\"交通费\":\"0.00\",\"订票手续费\":\"0.00\",\"退改签费\":\"0.00\",\"保险费\":\"0.00\",\"商旅订单供应商名称\":\"\",\"商旅金额（本位币）\":\"0.00\",\"餐饮费\":\"0.00\",\"住宿费\":\"0.00\",\"其他费用\":\"0.00\",\"出差天数\":\"0\",\"补助标准\":\"0.00\",\"补助金额\":\"0.00\",\"报销金额（原币）\":\"0.00\",\"报销金额（本位币）\":\"0.00\",\"来源\":\"手工录入\",\"总计\":\"0.00\",\"乘客身份证\":\"\",\"身份证号\":\"\",\"实报金额\":\"0.00\"}],\"发票明细\":[{\"序号\":\"1\",\"*发票类型\":\"电子发票(增值税专用发票)\",\"发票号码\":\"24422000000051972804\",\"发票代码\":\"\",\"校验码(后六位)\":\"24422000000051972804\",\"开票日期\":\"2024-05-18\",\"*价税合计\":\"1,996.00\",\"扣除费用\":\"0.00\",\"*不含税金额\":\"1,883.02\",\"税率（%）\":\"6%\",\"*税额\":\"112.98\",\"*验证状态\":\"查验成功\",\"原币币种\":\"CNY-人民币\",\"汇率\":\"1.000000\",\"*可抵扣税额（原币）\":\"112.98\",\"可抵扣税额（本位币）\":\"112.98\",\"备注\":\"2804754\",\"机票票价\":\"1,996.00\",\"自定义数值20\":\"直接汇率\",\"税码\":\"\",\"自定义文本4\":\"0\",\"有效税额\":\"112.98\",\"开票单位\":\"\",\"销售方名称\":\"武汉江城明珠酒店有限责任公司\",\"销售销方税号\":\"914201007819566969\",\"是否旅客运输服务\":\"否\"}],\"费用分摊\":[{\"序号\":\"1\",\"*业务科目\":\"管理费用-差旅交通费-差旅费\",\"预算科目名称\":\"差旅费\",\"预算科目\":\"管理费用-差旅交通费-差旅费\",\"*项目名称\":\"不适用\",\"*计税方法\":\"一般计税\",\"专项项目\":\"\",\"增减变动\":\"\",\"*费用承担单位\":\"国内区域中心\",\"部门\":\"华中区域中心\",\"分摊金额\":\"1,996.00\",\"*分摊金额（本位币）\":\"1,996.00\",\"可抵扣税额\":\"112.98\",\"不含税金额（原币）\":\"0.00\",\"不含税金额（本位币）\":\"1,883.02\",\"交通费可抵扣金额\":\"0.00\",\"备注\":\"\",\"预算科目id\":\"\",\"不含税分摊金额\":\"1,883.02\",\"专项项目类别编号\":\"\",\"增减变动类别编号\":\"1\"}],\"支付信息\":[{\"序号\":\"1\",\"资金计划\":\"\",\"现金流量\":\"\",\"*支付方式\":\"银企直联\",\"*交易币种\":\"CNY-人民币\",\"交易金额（原币）\":\"1,996.00\",\"*交易汇率\":\"1.000000\",\"交易金额（本位币）\":\"1,996.00\",\"付款账户名\":\"\",\"付款银行账户\":\"\",\"支付币种\":\"\",\"支付金额原币汇率\":\"1.0000\",\"支付金额（原币）\":\"1996.00\",\"*收款方性质\":\"内部员工\",\"*收款方\":\"张斌强\",\"收款银行账号\":\"6222001001121244785\",\"收款账户开户行\":\"中国工商银行股份有限公司上海市浦东大道支行\",\"收款方户名\":\"张斌强\",\"收款账户省份\":\"上海市\",\"收款账户城市\":\"上海市\",\"汇率\":\"1.000000\",\"现金流量类型\":\"\",\"挂账金额（原币）\":\"0.00\",\"挂账金额（本位币）\":\"0.00\",\"转账附言\":\"华中区域中心张斌强经手郑州国际陆港用户武汉住宿费\",\"项目名称\":\"\",\"付款账户内外部标识\":\"\",\"资金中心所属单位\":\"\",\"已付金额本币\":\"0.00\",\"已付金额\":\"0.00\",\"付款账户id\":\"\",\"自定义文本4\":\"\",\"自定义文本6\":\"dd7746cc-c142-f9c7-017f-1e6f7b058a8a\",\"自定义文本7\":\"0\"}]},\"Attachments\":[{\"serialNumber\":\"0\",\"fileUrl\":\"http://172.0.0.3:9001/filestransfer/download?filekey=6d5ff6e20de40724a7dd95a67587d6fe74a13824\",\"fileExtension\":\"png\",\"attachType\":\"\",\"Attachments\":{\"detailKey1\":\"\",\"detailKey2\":\"\"}},{\"serialNumber\":\"1\",\"fileUrl\":\"http://172.0.0.3:9001/filestransfer/download?filekey=52c0dd5d618ad8c0bca474fd5b7c1777da239b02\",\"fileExtension\":\"jpg\",\"attachType\":\"\",\"Attachments\":{\"detailKey1\":\"\",\"detailKey2\":\"\"}},{\"serialNumber\":\"2\",\"fileUrl\":\"http://172.0.0.3:9001/filestransfer/download?filekey=52a0446fa90a2c646bcada731faeaa3a9a493dd5\",\"fileExtension\":\"pdf\",\"attachType\":\"\",\"Attachments\":{\"detailKey1\":\"\",\"detailKey2\":\"\"}},{\"serialNumber\":\"3\",\"fileUrl\":\"http://172.0.0.3:9001/filestransfer/download?filekey=1285f923418f415f497a93a4f0d70cee8f94e81f\",\"fileExtension\":\"pdf\",\"attachType\":\"\",\"Attachments\":{\"detailKey1\":\"\",\"detailKey2\":\"\"}},{\"serialNumber\":\"4\",\"fileUrl\":\"http://172.0.0.3:9001/filestransfer/download?filekey=55e1acbbf04cefce183b952b2064ae705fa0d501\",\"fileExtension\":\"pdf\",\"attachType\":\"\",\"Attachments\":{\"detailKey1\":\"\",\"detailKey2\":\"\"}},{\"serialNumber\":\"5\",\"fileUrl\":\"http://172.0.0.3:9001/filestransfer/download?filekey=54a1622450d533995fc8f7d82935b3150a6ce7b7\",\"fileExtension\":\"jpg\",\"attachType\":\"\",\"Attachments\":{\"detailKey1\":\"\",\"detailKey2\":\"\"}},{\"serialNumber\":\"6\",\"fileUrl\":\"http://172.0.0.3:9001/filestransfer/download?filekey=8e6c21ba326990e94e18a49844ab26c8a7279e6a\",\"fileExtension\":\"pdf\",\"attachType\":\"\",\"Attachments\":{\"detailKey1\":\"\",\"detailKey2\":\"\"}}]}";

        // 原单数据添加
        JSONObject fObjReort = new JSONObject();
        fObjReort.put("name", "原单数据");
        JSONObject fObjReortHead = new JSONObject();
        JSONObject info = JSONObject.parseObject(jsonStr);
        fObjReortHead = info.getJSONObject("Basic");
        fObjReortHead.putAll(info.getJSONObject("Detail"));
        fObjReort.put("data", fObjReortHead);
        System.out.println(fObjReort.toJSONString());
    }
}
